<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>The led and delay abstractions - Discovery</title>


        <!-- Custom HTML head -->
        
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="Discover the world of microcontrollers through Rust">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="../favicon.svg">
        <link rel="shortcut icon" href="../favicon.png">
        <link rel="stylesheet" href="../css/variables.css">
        <link rel="stylesheet" href="../css/general.css">
        <link rel="stylesheet" href="../css/chrome.css">
        <link rel="stylesheet" href="../css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="../fonts/fonts.css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../highlight.css">
        <link rel="stylesheet" href="../tomorrow-night.css">
        <link rel="stylesheet" href="../ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        <link rel="stylesheet" href="../custom.css">

    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "../";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="../index.html">Introduction</a></li><li class="chapter-item expanded "><a href="../01-background/index.html"><strong aria-hidden="true">1.</strong> Background</a></li><li class="chapter-item expanded "><a href="../02-requirements/index.html"><strong aria-hidden="true">2.</strong> Hardware/knowledge requirements</a></li><li class="chapter-item expanded "><a href="../03-setup/index.html"><strong aria-hidden="true">3.</strong> Setting up a development environment</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../03-setup/linux.html"><strong aria-hidden="true">3.1.</strong> Linux</a></li><li class="chapter-item expanded "><a href="../03-setup/windows.html"><strong aria-hidden="true">3.2.</strong> Windows</a></li><li class="chapter-item expanded "><a href="../03-setup/macos.html"><strong aria-hidden="true">3.3.</strong> macOS</a></li><li class="chapter-item expanded "><a href="../03-setup/verify.html"><strong aria-hidden="true">3.4.</strong> Verify the installation</a></li></ol></li><li class="chapter-item expanded "><a href="../04-meet-your-hardware/index.html"><strong aria-hidden="true">4.</strong> Meet your hardware</a></li><li class="chapter-item expanded "><a href="../05-led-roulette/index.html"><strong aria-hidden="true">5.</strong> LED roulette</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../05-led-roulette/build-it.html"><strong aria-hidden="true">5.1.</strong> Build it</a></li><li class="chapter-item expanded "><a href="../05-led-roulette/flash-it.html"><strong aria-hidden="true">5.2.</strong> Flash it</a></li><li class="chapter-item expanded "><a href="../05-led-roulette/debug-it.html"><strong aria-hidden="true">5.3.</strong> Debug it</a></li><li class="chapter-item expanded "><a href="../05-led-roulette/the-led-and-delay-abstractions.html" class="active"><strong aria-hidden="true">5.4.</strong> The led and delay abstractions</a></li><li class="chapter-item expanded "><a href="../05-led-roulette/the-challenge.html"><strong aria-hidden="true">5.5.</strong> The challenge</a></li><li class="chapter-item expanded "><a href="../05-led-roulette/my-solution.html"><strong aria-hidden="true">5.6.</strong> My solution</a></li></ol></li><li class="chapter-item expanded "><a href="../06-hello-world/index.html"><strong aria-hidden="true">6.</strong> Hello, world!</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../06-hello-world/panic.html"><strong aria-hidden="true">6.1.</strong> panic!</a></li></ol></li><li class="chapter-item expanded "><a href="../07-registers/index.html"><strong aria-hidden="true">7.</strong> Registers</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../07-registers/rtrm.html"><strong aria-hidden="true">7.1.</strong> RTRM</a></li><li class="chapter-item expanded "><a href="../07-registers/optimization.html"><strong aria-hidden="true">7.2.</strong> (mis)Optimization</a></li><li class="chapter-item expanded "><a href="../07-registers/bad-address.html"><strong aria-hidden="true">7.3.</strong> 0xBAAAAAAD address</a></li><li class="chapter-item expanded "><a href="../07-registers/spooky-action-at-a-distance.html"><strong aria-hidden="true">7.4.</strong> Spooky action at a distance</a></li><li class="chapter-item expanded "><a href="../07-registers/type-safe-manipulation.html"><strong aria-hidden="true">7.5.</strong> Type safe manipulation</a></li></ol></li><li class="chapter-item expanded "><a href="../08-leds-again/index.html"><strong aria-hidden="true">8.</strong> LEDs, again</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../08-leds-again/power.html"><strong aria-hidden="true">8.1.</strong> Power</a></li><li class="chapter-item expanded "><a href="../08-leds-again/configuration.html"><strong aria-hidden="true">8.2.</strong> Configuration</a></li><li class="chapter-item expanded "><a href="../08-leds-again/the-solution.html"><strong aria-hidden="true">8.3.</strong> The solution</a></li></ol></li><li class="chapter-item expanded "><a href="../09-clocks-and-timers/index.html"><strong aria-hidden="true">9.</strong> Clocks and timers</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../09-clocks-and-timers/for-loop-delays.html"><strong aria-hidden="true">9.1.</strong> for loop delays</a></li><li class="chapter-item expanded "><a href="../09-clocks-and-timers/nop.html"><strong aria-hidden="true">9.2.</strong> NOP</a></li><li class="chapter-item expanded "><a href="../09-clocks-and-timers/one-shot-timer.html"><strong aria-hidden="true">9.3.</strong> One-shot timer</a></li><li class="chapter-item expanded "><a href="../09-clocks-and-timers/initialization.html"><strong aria-hidden="true">9.4.</strong> Initialization</a></li><li class="chapter-item expanded "><a href="../09-clocks-and-timers/busy-waiting.html"><strong aria-hidden="true">9.5.</strong> Busy waiting</a></li><li class="chapter-item expanded "><a href="../09-clocks-and-timers/putting-it-all-together.html"><strong aria-hidden="true">9.6.</strong> Putting it all together</a></li></ol></li><li class="chapter-item expanded "><a href="../10-serial-communication/index.html"><strong aria-hidden="true">10.</strong> Serial communication</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../10-serial-communication/nix-tooling.html"><strong aria-hidden="true">10.1.</strong> *nix tooling</a></li><li class="chapter-item expanded "><a href="../10-serial-communication/windows-tooling.html"><strong aria-hidden="true">10.2.</strong> Windows tooling</a></li><li class="chapter-item expanded "><a href="../10-serial-communication/loopbacks.html"><strong aria-hidden="true">10.3.</strong> Loopbacks</a></li></ol></li><li class="chapter-item expanded "><a href="../11-usart/index.html"><strong aria-hidden="true">11.</strong> USART</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../11-usart/send-a-single-byte.html"><strong aria-hidden="true">11.1.</strong> Send a single byte</a></li><li class="chapter-item expanded "><a href="../11-usart/send-a-string.html"><strong aria-hidden="true">11.2.</strong> Send a string</a></li><li class="chapter-item expanded "><a href="../11-usart/buffer-overrun.html"><strong aria-hidden="true">11.3.</strong> Buffer overrun</a></li><li class="chapter-item expanded "><a href="../11-usart/uprintln.html"><strong aria-hidden="true">11.4.</strong> uprintln!</a></li><li class="chapter-item expanded "><a href="../11-usart/receive-a-single-byte.html"><strong aria-hidden="true">11.5.</strong> Receive a single byte</a></li><li class="chapter-item expanded "><a href="../11-usart/echo-server.html"><strong aria-hidden="true">11.6.</strong> Echo server</a></li><li class="chapter-item expanded "><a href="../11-usart/reverse-a-string.html"><strong aria-hidden="true">11.7.</strong> Reverse a string</a></li><li class="chapter-item expanded "><a href="../11-usart/my-solution.html"><strong aria-hidden="true">11.8.</strong> My solution</a></li></ol></li><li class="chapter-item expanded "><a href="../12-bluetooth-setup/index.html"><strong aria-hidden="true">12.</strong> Bluetooth setup</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../12-bluetooth-setup/linux.html"><strong aria-hidden="true">12.1.</strong> Linux</a></li><li class="chapter-item expanded "><a href="../12-bluetooth-setup/loopback.html"><strong aria-hidden="true">12.2.</strong> Loopback</a></li><li class="chapter-item expanded "><a href="../12-bluetooth-setup/at-commands.html"><strong aria-hidden="true">12.3.</strong> AT commands</a></li></ol></li><li class="chapter-item expanded "><a href="../13-serial-over-bluetooth/index.html"><strong aria-hidden="true">13.</strong> Serial over Bluetooth</a></li><li class="chapter-item expanded "><a href="../14-i2c/index.html"><strong aria-hidden="true">14.</strong> I2C</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../14-i2c/the-general-protocol.html"><strong aria-hidden="true">14.1.</strong> The general protocol</a></li><li class="chapter-item expanded "><a href="../14-i2c/lsm303dlhc.html"><strong aria-hidden="true">14.2.</strong> LSM303DLHC</a></li><li class="chapter-item expanded "><a href="../14-i2c/read-a-single-register.html"><strong aria-hidden="true">14.3.</strong> Read a single register</a></li><li class="chapter-item expanded "><a href="../14-i2c/the-solution.html"><strong aria-hidden="true">14.4.</strong> The solution</a></li><li class="chapter-item expanded "><a href="../14-i2c/read-several-registers.html"><strong aria-hidden="true">14.5.</strong> Read several registers</a></li></ol></li><li class="chapter-item expanded "><a href="../15-led-compass/index.html"><strong aria-hidden="true">15.</strong> LED compass</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../15-led-compass/take-1.html"><strong aria-hidden="true">15.1.</strong> Take 1</a></li><li class="chapter-item expanded "><a href="../15-led-compass/solution-1.html"><strong aria-hidden="true">15.2.</strong> Solution 1</a></li><li class="chapter-item expanded "><a href="../15-led-compass/take-2.html"><strong aria-hidden="true">15.3.</strong> Take 2</a></li><li class="chapter-item expanded "><a href="../15-led-compass/solution-2.html"><strong aria-hidden="true">15.4.</strong> Solution 2</a></li><li class="chapter-item expanded "><a href="../15-led-compass/magnitude.html"><strong aria-hidden="true">15.5.</strong> Magnitude</a></li><li class="chapter-item expanded "><a href="../15-led-compass/calibration.html"><strong aria-hidden="true">15.6.</strong> Calibration</a></li></ol></li><li class="chapter-item expanded "><a href="../16-punch-o-meter/index.html"><strong aria-hidden="true">16.</strong> Punch-o-meter</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../16-punch-o-meter/gravity-is-up.html"><strong aria-hidden="true">16.1.</strong> Gravity is up?</a></li><li class="chapter-item expanded "><a href="../16-punch-o-meter/the-challenge.html"><strong aria-hidden="true">16.2.</strong> The challenge</a></li><li class="chapter-item expanded "><a href="../16-punch-o-meter/my-solution.html"><strong aria-hidden="true">16.3.</strong> My solution</a></li></ol></li><li class="chapter-item expanded "><a href="../explore.html"><strong aria-hidden="true">17.</strong> What's left for you to explore</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><a href="../appendix/1-general-troubleshooting/index.html">General troubleshooting</a></li><li class="chapter-item expanded affix "><a href="../appendix/2-how-to-use-gdb/index.html">How to use GDB</a></li><li class="spacer"></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">Discovery</h1>

                    <div class="right-buttons">
                        <a href="../print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                        <a href="https://github.com/rust-embedded/discovery/" title="Git repository" aria-label="Git repository">
                            <i id="git-repository-button" class="fa fa-github"></i>
                        </a>

                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="the-led-and-delay-abstractions"><a class="header" href="#the-led-and-delay-abstractions">The <code>Led</code> and <code>Delay</code> abstractions</a></h1>
<p>Now, I'm going to introduce two high level abstractions that we'll use to implement the LED roulette
application.</p>
<p>The auxiliary crate, <code>aux5</code>, exposes an initialization function called <code>init</code>. When called this
function returns two values packed in a tuple: a <code>Delay</code> value and a <code>LedArray</code> value.</p>
<p><code>Delay</code> can be used to block your program for a specified amount of milliseconds.</p>
<p><code>LedArray</code> is an array of eight <code>Led</code>s. Each <code>Led</code> represents one of the LEDs on the F3 board,
and exposes two methods: <code>on</code> and <code>off</code> which can be used to turn the LED on or off, respectively.</p>
<p>Let's try out these two abstractions by modifying the starter code to look like this:</p>
<pre><pre class="playground"><code class="language-rust">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use aux5::{entry, Delay, DelayMs, LedArray, OutputSwitch};

#[entry]
fn main() -&gt; ! {
    let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

    let half_period = 500_u16;

    loop {
        leds[0].on().ok();
        delay.delay_ms(half_period);

        leds[0].off().ok();
        delay.delay_ms(half_period);
    }
}
</code></pre></pre>
<p>Now build it:</p>
<pre><code class="language-console">cargo build
</code></pre>
<blockquote>
<p><strong>NOTE</strong> It's possible to forget to rebuild the program <em>before</em> starting a GDB session; this
omission can lead to very confusing debug sessions. To avoid this problem you can call just <code>cargo run</code>
instead of <code>cargo build</code>; <code>cargo run</code>. The <code>cargo run</code> command will build <em>and</em> start a debug
session ensuring you never forget to recompile your program.</p>
</blockquote>
<p>Now we'll run and repeat the flashing procedure as we did in the previous section
but with the new program. I'll let you type in the <code>cargo run</code>, <em>this will get easier shortly</em>. :)
Note: </p>
<p>Don't forget to start <code>openocd</code> (debugger) on a separate terminal. Otherwise <code>target remote :3333</code> won't work! </p>
<pre><code class="language-console">$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `arm-none-eabi-gdb -q ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette...

(gdb) target remote :3333
Remote debugging using :3333
led_roulette::__cortex_m_rt_main_trampoline () at ~/embedded-discovery/src/05-led-roulette/src/main.rs:7
7       #[entry]

(gdb) load
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x52c0 lma 0x8000194
Loading section .rodata, size 0xb50 lma 0x8005454
Start address 0x08000194, load size 24484
Transfer rate: 21 KB/sec, 6121 bytes/write.

(gdb) break main
Breakpoint 1 at 0x8000202: file ~/embedded-discovery/src/05-led-roulette/src/main.rs, line 7.
Note: automatically using hardware breakpoints for read-only addresses.

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main_trampoline ()
    at ~/embedded-discovery/src/05-led-roulette/src/main.rs:7
7       #[entry]

(gdb) step
led_roulette::__cortex_m_rt_main () at ~/embedded-discovery/src/05-led-roulette/src/main.rs:9
9           let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

(gdb)
</code></pre>
<p>OK. Let's step through the code. This time, we'll use the <code>next</code> command instead of <code>step</code>. The
difference is that the <code>next</code> command will step <em>over</em> function calls instead of going inside them.</p>
<pre><code>(gdb) next
11          let half_period = 500_u16;

(gdb) next
13          loop {

(gdb) next
14              leds[0].on().ok();

(gdb) next
15              delay.delay_ms(half_period);
</code></pre>
<p>After executing the <code>leds[0].on().ok()</code> statement, you should see a red LED, the one pointing North,
turn on.</p>
<p>Let's continue stepping over the program:</p>
<pre><code>(gdb) next
17              leds[0].off().ok();

(gdb) next
18              delay.delay_ms(half_period);
</code></pre>
<p>The <code>delay_ms</code> call will block the program for half a second but you may not notice because the
<code>next</code> command also takes some time to execute. However, after stepping over the <code>leds[0].off()</code>
statement you should see the red LED turn off.</p>
<p>You can already guess what this program does. Let it run uninterrupted using the <code>continue</code> command.</p>
<pre><code>(gdb) continue
Continuing.
</code></pre>
<p>Now, let's do something more interesting. We are going to modify the behavior of our program using
GDB.</p>
<p>First, let's stop the infinite loop by hitting <code>Ctrl+C</code>. You'll probably end up somewhere inside
<code>Led::on</code>, <code>Led::off</code> or <code>delay_ms</code>:</p>
<pre><code>^C
Program received signal SIGINT, Interrupt.
0x08003434 in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053
</code></pre>
<p>In my case, the program stopped its execution inside a <code>read_volatile</code> function. GDB output shows
some interesting information about that: <code>core::ptr::read_volatile (src=0xe000e010)</code>. This means
that the function comes from the <code>core</code> crate and that it was called with argument <code>src = 0xe000e010</code>.</p>
<p>Just so you know, a more explicit way to show the arguments of a function is to use the <code>info args</code>
command:</p>
<pre><code>(gdb) info args
src = 0xe000e010
</code></pre>
<p>Regardless of where your program may have stopped you can always look at the output of the
<code>backtrace</code> command (<code>bt</code> for short) to learn how it got there:</p>
<pre><code>(gdb) backtrace
#0  0x08003434 in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053
#1  0x08002d66 in vcell::VolatileCell&lt;u32&gt;::get&lt;u32&gt; (self=0xe000e010) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/vcell-0.1.3/src/lib.rs:33
#2  volatile_register::RW&lt;u32&gt;::read&lt;u32&gt; (self=0xe000e010) at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/volatile-register-0.2.0/src/lib.rs:75
#3  cortex_m::peripheral::SYST::has_wrapped (self=0x20009fa4)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/peripheral/syst.rs:136
#4  0x08003004 in stm32f3xx_hal::delay::{{impl}}::delay_us (self=0x20009fa4, us=500000)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:58
#5  0x08002f3e in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:32
#6  0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38
#7  0x0800024c in led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:15
#8  0x08000206 in led_roulette::__cortex_m_rt_main_trampoline () at src/05-led-roulette/src/main.rs:7
</code></pre>
<p><code>backtrace</code> will print a trace of function calls from the current function down to main.</p>
<p>Back to our topic. To do what we are after, first, we have to return to the <code>main</code> function. We can
do that using the <code>finish</code> command. This command resumes the program execution and stops it again
right after the program returns from the current function. We'll have to call it several times.</p>
<pre><code>(gdb) finish
Run till exit from #0  0x08003434 in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1053
cortex_m::peripheral::SYST::has_wrapped (self=0x20009fa4)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/peripheral/syst.rs:136
136             self.csr.read() &amp; SYST_CSR_COUNTFLAG != 0
Value returned is $1 = 5

(..)

(gdb) finish
Run till exit from #0  0x08002f3e in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:32
0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38
38              self.delay_ms(u32(ms));

(gdb) finish
Run till exit from #0  0x08002f80 in stm32f3xx_hal::delay::{{impl}}::delay_ms (self=0x20009fa4, ms=500)
    at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/stm32f3xx-hal-0.5.0/src/delay.rs:38
0x0800024c in led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:15
15              delay.delay_ms(half_period);
</code></pre>
<p>We are back in <code>main</code>. We have a local variable in here: <code>half_period</code></p>
<pre><code>(gdb) print half_period
$3 = 500
</code></pre>
<p>Now, we are going to modify this variable using the <code>set</code> command:</p>
<pre><code>(gdb) set half_period = 100

(gdb) print half_period
$5 = 100
</code></pre>
<p>If you let program run free again using the <code>continue</code> command, you <strong>might</strong> see that the LED will
blink at a much faster rate now, but more likely the blink rate didn't change. <strong>What happened?</strong></p>
<p>Let's stop the program with <code>Ctrl+C</code> and then set a break point at <code>main:14</code>.</p>
<pre><code class="language-console">(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
core::cell::UnsafeCell&lt;u32&gt;::get&lt;u32&gt; (self=0x20009fa4)
    at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:1711
1711        pub const fn get(&amp;self) -&gt; *mut T {
</code></pre>
<p>Then set a break point at <code>main.rs:14</code> and <code>continue</code></p>
<pre><code class="language-console">(gdb) break main.rs:14
Breakpoint 2 at 0x8000236: file src/05-led-roulette/src/main.rs, line 14.
(gdb) continue
Continuing.

Breakpoint 2, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:14
14              leds[0].on().ok();
</code></pre>
<p>Now open your terminal window so it's about 80 lines long an 170 characters wide if possible.</p>
<blockquote>
<p><strong>NOTE</strong> If you can't open the terminal that large, no problem you'll just see
<code>--Type &lt;RET&gt; for more, q to quit, c to continue without paging--</code> so just type return
until you see the <code>(gdb)</code> prompt. Then scroll your terminal window to
see the results.</p>
</blockquote>
<pre><code class="language-console">(gdb) disassemble /m
Dump of assembler code for function _ZN12led_roulette18__cortex_m_rt_main17h51e7c3daad2af251E:
8       fn main() -&gt; ! {
   0x08000208 &lt;+0&gt;:     push    {r7, lr}
   0x0800020a &lt;+2&gt;:     mov     r7, sp
   0x0800020c &lt;+4&gt;:     sub     sp, #64 ; 0x40
   0x0800020e &lt;+6&gt;:     add     r0, sp, #32

9           let (mut delay, mut leds): (Delay, LedArray) = aux5::init();
   0x08000210 &lt;+8&gt;:     bl      0x8000302 &lt;aux5::init&gt;
   0x08000214 &lt;+12&gt;:    b.n     0x8000216 &lt;led_roulette::__cortex_m_rt_main+14&gt;
   0x08000216 &lt;+14&gt;:    add     r0, sp, #32
   0x08000218 &lt;+16&gt;:    add     r1, sp, #4
   0x0800021a &lt;+18&gt;:    ldmia.w r0, {r2, r3, r4, r12, lr}
   0x0800021e &lt;+22&gt;:    stmia.w r1, {r2, r3, r4, r12, lr}
   0x08000222 &lt;+26&gt;:    ldr     r0, [sp, #52]   ; 0x34
   0x08000224 &lt;+28&gt;:    ldr     r1, [sp, #56]   ; 0x38
   0x08000226 &lt;+30&gt;:    str     r1, [sp, #28]
   0x08000228 &lt;+32&gt;:    str     r0, [sp, #24]
   0x0800022a &lt;+34&gt;:    mov.w   r0, #500        ; 0x1f4

10
11          let half_period = 500_u16;
   0x0800022e &lt;+38&gt;:    strh.w  r0, [r7, #-2]

12
13          loop {
   0x08000232 &lt;+42&gt;:    b.n     0x8000234 &lt;led_roulette::__cortex_m_rt_main+44&gt;
   0x08000234 &lt;+44&gt;:    add     r0, sp, #24
   0x08000268 &lt;+96&gt;:    b.n     0x8000234 &lt;led_roulette::__cortex_m_rt_main+44&gt;

14              leds[0].on().ok();
=&gt; 0x08000236 &lt;+46&gt;:    bl      0x80001ec &lt;switch_hal::output::{{impl}}::on&lt;stm32f3xx_hal::gpio::gpioe::PEx&lt;stm32f3xx_hal::gpio::Output&lt;stm32f3xx_hal::gpio::PushPull&gt;&gt;&gt;&gt;
   0x0800023a &lt;+50&gt;:    b.n     0x800023c &lt;led_roulette::__cortex_m_rt_main+52&gt;
   0x0800023c &lt;+52&gt;:    bl      0x8000594 &lt;core::result::Result&lt;(), core::convert::Infallible&gt;::ok&lt;(),core::convert::Infallible&gt;&gt;
   0x08000240 &lt;+56&gt;:    b.n     0x8000242 &lt;led_roulette::__cortex_m_rt_main+58&gt;
   0x08000242 &lt;+58&gt;:    add     r0, sp, #4
   0x08000244 &lt;+60&gt;:    mov.w   r1, #500        ; 0x1f4

15              delay.delay_ms(half_period);
   0x08000248 &lt;+64&gt;:    bl      0x8002f5c &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
   0x0800024c &lt;+68&gt;:    b.n     0x800024e &lt;led_roulette::__cortex_m_rt_main+70&gt;
   0x0800024e &lt;+70&gt;:    add     r0, sp, #24

16
17              leds[0].off().ok();
   0x08000250 &lt;+72&gt;:    bl      0x800081a &lt;switch_hal::output::{{impl}}::off&lt;stm32f3xx_hal::gpio::gpioe::PEx&lt;stm32f3xx_hal::gpio::Output&lt;stm32f3xx_hal::gpio::PushPull&gt;&gt;&gt;&gt;
   0x08000254 &lt;+76&gt;:    b.n     0x8000256 &lt;led_roulette::__cortex_m_rt_main+78&gt;
   0x08000256 &lt;+78&gt;:    bl      0x8000594 &lt;core::result::Result&lt;(), core::convert::Infallible&gt;::ok&lt;(),core::convert::Infallible&gt;&gt;
   0x0800025a &lt;+82&gt;:    b.n     0x800025c &lt;led_roulette::__cortex_m_rt_main+84&gt;
   0x0800025c &lt;+84&gt;:    add     r0, sp, #4
   0x0800025e &lt;+86&gt;:    mov.w   r1, #500        ; 0x1f4

18              delay.delay_ms(half_period);
   0x08000262 &lt;+90&gt;:    bl      0x8002f5c &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
   0x08000266 &lt;+94&gt;:    b.n     0x8000268 &lt;led_roulette::__cortex_m_rt_main+96&gt;

End of assembler dump.
</code></pre>
<p>In the above dump the reason the delay didn't change was because the compiler
recognized that half_period didn't change and instead in the two places where
<code>delay.delay_ms(half_period);</code> is called we see <code>mov.w r1, #500</code>. So changing the
value of <code>half_period</code> does nothing!</p>
<pre><code class="language-console">   0x08000244 &lt;+60&gt;:    mov.w   r1, #500        ; 0x1f4

15              delay.delay_ms(half_period);
   0x08000248 &lt;+64&gt;:    bl      0x8002f5c &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;

(..)

   0x0800025e &lt;+86&gt;:    mov.w   r1, #500        ; 0x1f4

18              delay.delay_ms(half_period);
   0x08000262 &lt;+90&gt;:    bl      0x8002f5c &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
</code></pre>
<p>One solution to the problem is to wrap <code>half_period</code> in a <code>Volatile</code> as shown below.</p>
<pre><code class="language-console">#![deny(unsafe_code)]
#![no_main]
#![no_std]

use volatile::Volatile;
use aux5::{Delay, DelayMs, LedArray, OutputSwitch, entry};

#[entry]
fn main() -&gt; ! {
    let (mut delay, mut leds): (Delay, LedArray) = aux5::init();

    let mut half_period = 500_u16;
    let v_half_period = Volatile::new(&amp;mut half_period);

    loop {
        leds[0].on().ok();
        delay.delay_ms(v_half_period.read());

        leds[0].off().ok();
        delay.delay_ms(v_half_period.read());
    }
}

</code></pre>
<p>Edit <code>Cargo.toml</code> adding <code>volatile = &quot;0.4.3&quot;</code> in the <code>[dependencies]</code> section.</p>
<pre><code class="language-console">[dependencies]
aux5 = { path = &quot;auxiliary&quot; }
volatile = &quot;0.4.3&quot;
</code></pre>
<p>With the above code using <code>Volatile</code> you can now change <code>half_period</code> and
you'll be able to experiment with different values. Here is the list of
commands followed by an explanation; <code># xxxx</code> to demonstrate.</p>
<pre><code>$ cargo run --target thumbv7em-none-eabihf   # Compile and load the program into gdb
(gdb) target remote :3333           # Connect to STM32F3DISCOVERY board from PC
(gdb) load                          # Flash program
(gdb) break main.rs:16              # Set breakpoint 1 at top of loop
(gdb) continue                      # Continue, will stop at main.rs:16
(gdb) disable 1                     # Disable breakpoint 1
(gdb) set print asm-demangle on     # Enable asm-demangle
(gdb) disassemble /m                # Disassemble main function
(gdb) continue                      # Led blinking on for 1/2 sec then off 1/2 sec
^C                                  # Stop with Ctrl+C
(gdb) enable 1                      # Enable breakpiont 1
(gdb) continue                      # Continue, will stop at main.rs:16
(gdb) print half_period             # Print half_period result is 500
(gdb) set half_period = 2000        # Set half_period to 2000ms
(gdb) print half_period             # Print half_period and result is 2000
(gdb) disable 1                     # Disable breakpoint 1
(gdb) continue                      # Led blinking on for 2 secs then off 2 sec
^C                                  # Stop with Ctrl+C
(gdb) quit                          # Quit gdb
</code></pre>
<p>The critical changes are at lines 13, 17 and 20 in the source code which
you can see in the disassembly. At 13 we creating <code>v_half_period</code> and then
<code>read()</code> it's value in lines 17 and 20. This means that when we <code>set half_period = 2000</code>
the led will now be on for 2 seconds then off for 2 seconds.</p>
<pre><code class="language-console">$ cargo run --target thumbv7em-none-eabihf
   Compiling led-roulette v0.2.0 (~/embedded-discovery/src/05-led-roulette)
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
     Running `arm-none-eabi-gdb -q ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette`
Reading symbols from ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette...

(gdb) target remote :3333
Remote debugging using :3333
led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) load
Loading section .vector_table, size 0x194 lma 0x8000000
Loading section .text, size 0x5258 lma 0x8000194
Loading section .rodata, size 0xbd8 lma 0x80053ec
Start address 0x08000194, load size 24516
Transfer rate: 21 KB/sec, 6129 bytes/write.

(gdb) break main.rs:16
Breakpoint 1 at 0x8000246: file src/05-led-roulette/src/main.rs, line 16.
Note: automatically using hardware breakpoints for read-only addresses.

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) disable 1

(gdb) set print asm-demangle on

(gdb) disassemble /m
Dump of assembler code for function _ZN12led_roulette18__cortex_m_rt_main17he1f2bc7990b13731E:
9       fn main() -&gt; ! {
   0x0800020e &lt;+0&gt;:     push    {r7, lr}
   0x08000210 &lt;+2&gt;:     mov     r7, sp
   0x08000212 &lt;+4&gt;:     sub     sp, #72 ; 0x48
   0x08000214 &lt;+6&gt;:     add     r0, sp, #36     ; 0x24

10          let (mut delay, mut leds): (Delay, LedArray) = aux5::init();
   0x08000216 &lt;+8&gt;:     bl      0x800036a &lt;aux5::init&gt;
   0x0800021a &lt;+12&gt;:    b.n     0x800021c &lt;led_roulette::__cortex_m_rt_main+14&gt;
   0x0800021c &lt;+14&gt;:    add     r0, sp, #36     ; 0x24
   0x0800021e &lt;+16&gt;:    add     r1, sp, #8
   0x08000220 &lt;+18&gt;:    ldmia.w r0, {r2, r3, r4, r12, lr}
   0x08000224 &lt;+22&gt;:    stmia.w r1, {r2, r3, r4, r12, lr}
   0x08000228 &lt;+26&gt;:    ldr     r0, [sp, #56]   ; 0x38
   0x0800022a &lt;+28&gt;:    ldr     r1, [sp, #60]   ; 0x3c
   0x0800022c &lt;+30&gt;:    str     r1, [sp, #32]
   0x0800022e &lt;+32&gt;:    str     r0, [sp, #28]
   0x08000230 &lt;+34&gt;:    mov.w   r0, #500        ; 0x1f4

11
12          let mut half_period = 500_u16;
   0x08000234 &lt;+38&gt;:    strh.w  r0, [r7, #-6]
   0x08000238 &lt;+42&gt;:    subs    r0, r7, #6

13          let v_half_period = Volatile::new(&amp;mut half_period);
   0x0800023a &lt;+44&gt;:    bl      0x800033e &lt;volatile::Volatile&lt;&amp;mut u16, volatile::access::ReadWrite&gt;::new&lt;&amp;mut u16&gt;&gt;
   0x0800023e &lt;+48&gt;:    str     r0, [sp, #68]   ; 0x44
   0x08000240 &lt;+50&gt;:    b.n     0x8000242 &lt;led_roulette::__cortex_m_rt_main+52&gt;

14
15          loop {
   0x08000242 &lt;+52&gt;:    b.n     0x8000244 &lt;led_roulette::__cortex_m_rt_main+54&gt;
   0x08000244 &lt;+54&gt;:    add     r0, sp, #28
   0x08000288 &lt;+122&gt;:   b.n     0x8000244 &lt;led_roulette::__cortex_m_rt_main+54&gt;

16              leds[0].on().ok();
=&gt; 0x08000246 &lt;+56&gt;:    bl      0x800032c &lt;switch_hal::output::{{impl}}::on&lt;stm32f3xx_hal::gpio::gpioe::PEx&lt;stm32f3xx_hal::gpio::Output&lt;stm32f3xx_hal::gpio::PushPull&gt;&gt;&gt;&gt;
   0x0800024a &lt;+60&gt;:    b.n     0x800024c &lt;led_roulette::__cortex_m_rt_main+62&gt;
   0x0800024c &lt;+62&gt;:    bl      0x80005fc &lt;core::result::Result&lt;(), core::convert::Infallible&gt;::ok&lt;(),core::convert::Infallible&gt;&gt;
   0x08000250 &lt;+66&gt;:    b.n     0x8000252 &lt;led_roulette::__cortex_m_rt_main+68&gt;
   0x08000252 &lt;+68&gt;:    add     r0, sp, #68     ; 0x44

17              delay.delay_ms(v_half_period.read());
   0x08000254 &lt;+70&gt;:    bl      0x800034a &lt;volatile::Volatile&lt;&amp;mut u16, volatile::access::ReadWrite&gt;::read&lt;&amp;mut u16,u16,volatile::access::ReadWrite&gt;&gt;
   0x08000258 &lt;+74&gt;:    str     r0, [sp, #4]
   0x0800025a &lt;+76&gt;:    b.n     0x800025c &lt;led_roulette::__cortex_m_rt_main+78&gt;
   0x0800025c &lt;+78&gt;:    add     r0, sp, #8
   0x0800025e &lt;+80&gt;:    ldr     r1, [sp, #4]
   0x08000260 &lt;+82&gt;:    bl      0x8002fc4 &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
   0x08000264 &lt;+86&gt;:    b.n     0x8000266 &lt;led_roulette::__cortex_m_rt_main+88&gt;
   0x08000266 &lt;+88&gt;:    add     r0, sp, #28

18
19              leds[0].off().ok();
   0x08000268 &lt;+90&gt;:    bl      0x8000882 &lt;switch_hal::output::{{impl}}::off&lt;stm32f3xx_hal::gpio::gpioe::PEx&lt;stm32f3xx_hal::gpio::Output&lt;stm32f3xx_hal::gpio::PushPull&gt;&gt;&gt;&gt;
   0x0800026c &lt;+94&gt;:    b.n     0x800026e &lt;led_roulette::__cortex_m_rt_main+96&gt;
   0x0800026e &lt;+96&gt;:    bl      0x80005fc &lt;core::result::Result&lt;(), core::convert::Infallible&gt;::ok&lt;(),core::convert::Infallible&gt;&gt;
   0x08000272 &lt;+100&gt;:   b.n     0x8000274 &lt;led_roulette::__cortex_m_rt_main+102&gt;
   0x08000274 &lt;+102&gt;:   add     r0, sp, #68     ; 0x44

20              delay.delay_ms(v_half_period.read());
   0x08000276 &lt;+104&gt;:   bl      0x800034a &lt;volatile::Volatile&lt;&amp;mut u16, volatile::access::ReadWrite&gt;::read&lt;&amp;mut u16,u16,volatile::access::ReadWrite&gt;&gt;
   0x0800027a &lt;+108&gt;:   str     r0, [sp, #0]
   0x0800027c &lt;+110&gt;:   b.n     0x800027e &lt;led_roulette::__cortex_m_rt_main+112&gt;
   0x0800027e &lt;+112&gt;:   add     r0, sp, #8
   0x08000280 &lt;+114&gt;:   ldr     r1, [sp, #0]
   0x08000282 &lt;+116&gt;:   bl      0x8002fc4 &lt;stm32f3xx_hal::delay::{{impl}}::delay_ms&gt;
   0x08000286 &lt;+120&gt;:   b.n     0x8000288 &lt;led_roulette::__cortex_m_rt_main+122&gt;

End of assembler dump.

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x080037b2 in core::cell::UnsafeCell&lt;u32&gt;::get&lt;u32&gt; (self=0x20009fa0) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cell.rs:1716
1716        }

(gdb) enable 1

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) print half_period
$2 = 500

(gdb) disable 1

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x08003498 in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1052
1052        unsafe { intrinsics::volatile_load(src) }

(gdb) enable 1

(gdb) continue
Continuing.

Breakpoint 1, led_roulette::__cortex_m_rt_main () at src/05-led-roulette/src/main.rs:16
16              leds[0].on().ok();

(gdb) print half_period
$3 = 500

(gdb) set half_period = 2000

(gdb) print half_period
$4 = 2000

(gdb) disable 1

(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x0800348e in core::ptr::read_volatile&lt;u32&gt; (src=0xe000e010) at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1046
1046    pub unsafe fn read_volatile&lt;T&gt;(src: *const T) -&gt; T {

(gdb) q
Detaching from program: ~/embedded-discovery/target/thumbv7em-none-eabihf/debug/led-roulette, Remote target
Ending remote debugging.
[Inferior 1 (Remote target) detached]
</code></pre>
<p>Question! What happens if you start lowering the value of <code>half_period</code>? At what value of
<code>half_period</code> you can no longer see the LED blink?</p>
<p>Now, it's your turn to write a program.</p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                            <a rel="prev" href="../05-led-roulette/debug-it.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>

                            <a rel="next" href="../05-led-roulette/the-challenge.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                    <a rel="prev" href="../05-led-roulette/debug-it.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>

                    <a rel="next" href="../05-led-roulette/the-challenge.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
            </nav>

        </div>




        <script type="text/javascript">
            window.playground_copyable = true;
        </script>


        <script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../searcher.js" type="text/javascript" charset="utf-8"></script>

        <script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="../book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->


    </body>
</html>
